/* *
 * @file    app_adc.c
 * @author  Azolla (1228449928@qq.com)
 * @brief    
 * @version 0.1
 * @date    2022-09-19
 * 
 * @copyright Copyright (c) 2022
 * */
#include <string.h>
#include <stdio.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "driver/adc.h"

#if 1
#define TIMES              128 * 4
#define GET_UNIT(x)        ((x>>3) & 0x1)
 
#if  CONFIG_IDF_TARGET_ESP32S3
#define ADC_RESULT_BYTE     4
#define ADC_CONV_LIMIT_EN   0
#define ADC_CONV_MODE       ADC_CONV_SINGLE_UNIT_1 // ADC_CONV_BOTH_UNIT
#define ADC_OUTPUT_TYPE     ADC_DIGI_OUTPUT_FORMAT_TYPE2
#endif
 
#if 1 // CONFIG_IDF_TARGET_ESP32S3  
static uint16_t adc1_chan_mask = BIT(3);    // ADC1_CH3 -> IO4
// static uint16_t adc2_chan_mask = BIT(0);
static uint16_t adc2_chan_mask = 0;
static adc_channel_t channel[1] = {ADC1_CHANNEL_3};
#endif

static const char *TAG = "app_adc"; 

static void continuous_adc_init(uint16_t adc1_chan_mask, uint16_t adc2_chan_mask, adc_channel_t *channel, uint8_t channel_num)
{
    adc_digi_init_config_t adc_dma_config = {
        .max_store_buf_size = 1024,
        .conv_num_each_intr = TIMES,
        .adc1_chan_mask = adc1_chan_mask,
        .adc2_chan_mask = adc2_chan_mask,
    };
    ESP_ERROR_CHECK(adc_digi_initialize(&adc_dma_config));

    adc_digi_configuration_t dig_cfg = {
        .conv_limit_en = ADC_CONV_LIMIT_EN,
        .conv_limit_num = TIMES,
        .sample_freq_hz = 32 * 1000,  // SOC_ADC_SAMPLE_FREQ_THRES_HIGH
        .conv_mode = ADC_CONV_MODE,
        .format = ADC_OUTPUT_TYPE,
    };

    adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = {0};
    dig_cfg.pattern_num = channel_num;
    for (int i = 0; i < channel_num; i++) {
        uint8_t unit = GET_UNIT(channel[i]);
        uint8_t ch = channel[i] & 0x7;
        adc_pattern[i].atten = ADC_ATTEN_DB_11;  // 800mv  by about 11 dB (3.55 x) = 2.84V
        adc_pattern[i].channel = ch;
        adc_pattern[i].unit = unit;
        adc_pattern[i].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;
        #if 1
        ESP_LOGI(TAG, "adc_pattern[%d].atten is :%x", i, adc_pattern[i].atten);
        ESP_LOGI(TAG, "adc_pattern[%d].channel is :%x", i, adc_pattern[i].channel);
        ESP_LOGI(TAG, "adc_pattern[%d].unit is :%x", i, adc_pattern[i].unit);
        #endif
    }
    dig_cfg.adc_pattern = adc_pattern;
    ESP_ERROR_CHECK(adc_digi_controller_configure(&dig_cfg));
}

void adc_read_task(void *arg)
{
    esp_err_t ret;
    uint32_t ret_num = 0;
    uint8_t result[TIMES] = {0};
    memset(result, 0x00, TIMES);

    uint16_t total_num = 0;
   
    while (true) {
        // vTaskDelay(2000);
        adc_digi_start();  
        for (total_num = 0; total_num < TIMES; ) {
            ret = adc_digi_read_bytes(result, TIMES - total_num, &ret_num, ADC_MAX_DELAY); // ADC_MAX_DELAY
            if (ret == ESP_OK || ret == ESP_ERR_INVALID_STATE) { // 转化太快
                total_num += ret_num;
            }
        }
        adc_digi_stop();  // start -> read -> stop 这样就不会出现 ESP_ERR_INVALID_STATE
        ESP_LOGI("TASK:", "ret is 0x%x, ret_num is %d", ret, total_num);
         
        uint32_t adc_sum = 0;
        for (int i = 0; i < total_num; i += ADC_RESULT_BYTE) {
            adc_digi_output_data_t *p = (void*)&result[i];
            adc_sum += p->type2.data;
            printf("%d\n", p->type2.data);  // 用excel表格可以建立波形图！
            // ESP_LOGI(TAG, "Unit: %d, Channel: %d, Value: %d", p->type2.unit + 1, p->type2.channel, p->type2.data);
        } 
        printf("\n\n--------\n\n");
        ESP_LOGI(TAG, "adc_sum: %d", adc_sum/(total_num/4));
       
        vTaskDelay(2000);
    }
    vTaskDelete(NULL);
}


void app_adc_init(void)
{
    continuous_adc_init(adc1_chan_mask, adc2_chan_mask, channel, sizeof(channel) / sizeof(adc_channel_t));

    xTaskCreatePinnedToCore(adc_read_task, "adc_read_task", 3 * 1024, NULL, 6, NULL, APP_CPU_NUM);  
}

#endif
